<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
    

<head><meta name="generator" content="Hexo 3.8.0">
    <meta charset="utf-8">
    <meta name="keywords" content="WebRTC04KurentoDemo流程分析, 炫杉">
    <meta name="description" content="
今天的学习可以说是以失败告终了吧。也就知道了用js动态调试。大体看懂了participant.js和conference.js。但最大头的是kurento.js


关于频繁出现的 ICE candidate：ICE stands for">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="renderer" content="webkit|ie-stand|ie-comp">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <title>WebRTC04KurentoDemo流程分析 | 炫杉</title>
    <link rel="icon" type="image/png" href="/favicon.png">

    <link rel="stylesheet" type="text/css" href="/libs/awesome/css/font-awesome.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/materialize/css/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/aos/aos.css">
    <link rel="stylesheet" type="text/css" href="/libs/animate/animate.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/lightGallery/css/lightgallery.min.css">
    <link rel="stylesheet" type="text/css" href="/css/matery.css">
    <link rel="stylesheet" type="text/css" href="/css/my.css">

    <script src="/libs/jquery/jquery-2.2.0.min.js"></script>
<link rel="stylesheet" href="/css/prism-tomorrow.css" type="text/css">
<link rel="stylesheet" href="/css/prism-line-numbers.css" type="text/css"></head>

</head>

<body>

<header class="navbar-fixed">
    <nav id="headNav" class="bg-color nav-transparent">
        <div id="navContainer" class="container">
            <div class="nav-wrapper">
                <div class="brand-logo">
                    <a href="/" class="waves-effect waves-light">
                        
                        <img src="/medias/logo.png" class="logo-img hide-on-small-only">
                        
                        <span class="logo-span">炫杉</span>
                    </a>
                </div>
                <a href="#" data-activates="mobile-nav" class="button-collapse"><i class="fa fa-navicon"></i></a>
<ul class="right">
    
    <li class="hide-on-med-and-down">
        <a href="/" class="waves-effect waves-light">
            
            <i class="fa fa-home"></i>
            
            <span>Index</span>
        </a>
    </li>
    
    <li class="hide-on-med-and-down">
        <a href="/tags" class="waves-effect waves-light">
            
            <i class="fa fa-tags"></i>
            
            <span>Tags</span>
        </a>
    </li>
    
    <li class="hide-on-med-and-down">
        <a href="/categories" class="waves-effect waves-light">
            
            <i class="fa fa-bookmark"></i>
            
            <span>Categories</span>
        </a>
    </li>
    
    <li class="hide-on-med-and-down">
        <a href="/archives" class="waves-effect waves-light">
            
            <i class="fa fa-archive"></i>
            
            <span>Archives</span>
        </a>
    </li>
    
    <li class="hide-on-med-and-down">
        <a href="/about" class="waves-effect waves-light">
            
            <i class="fa fa-user-circle-o"></i>
            
            <span>About</span>
        </a>
    </li>
    
    <li class="hide-on-med-and-down">
        <a href="https://oo1.win" class="waves-effect waves-light">
            
            <i class="fa fa-star"></i>
            
            <span>Bookmark</span>
        </a>
    </li>
    
    <li>
        <a id="toggleSearch" class="waves-effect waves-light">
            <i id="searchIcon" class="mdi-action-search"></i>
        </a>
    </li>

</ul>

<div class="side-nav" id="mobile-nav">

    <div class="mobile-head bg-color">
        
        <img src="/medias/logo.png" class="logo-img circle responsive-img">
        
        <div class="logo-name">炫杉</div>
        <div class="logo-desc">
            
            提着鸟笼的老头站在一旁拍我肩膀 我猜他想的应该和我一样
            
        </div>
    </div>

    <ul class="menu-list mobile-menu-list">
        
        <li>
            <a href="/" class="waves-effect waves-light">
                
                <i class="fa fa-fw fa-home"></i>
                
                Index
            </a>
        </li>
        
        <li>
            <a href="/tags" class="waves-effect waves-light">
                
                <i class="fa fa-fw fa-tags"></i>
                
                Tags
            </a>
        </li>
        
        <li>
            <a href="/categories" class="waves-effect waves-light">
                
                <i class="fa fa-fw fa-bookmark"></i>
                
                Categories
            </a>
        </li>
        
        <li>
            <a href="/archives" class="waves-effect waves-light">
                
                <i class="fa fa-fw fa-archive"></i>
                
                Archives
            </a>
        </li>
        
        <li>
            <a href="/about" class="waves-effect waves-light">
                
                <i class="fa fa-fw fa-user-circle-o"></i>
                
                About
            </a>
        </li>
        
        <li>
            <a href="https://oo1.win" class="waves-effect waves-light">
                
                <i class="fa fa-fw fa-star"></i>
                
                Bookmark
            </a>
        </li>
        
        
    </ul>

    <div class="social-link"><a href="https://github.com/ixsim" class="tooltipped" target="_blank" data-tooltip="访问我的GitHub" data-position="top" data-delay="50">
    <i class="fa fa-github"></i>
</a>

<a href="mailto:chenjiayin1990@163.com" class="tooltipped" target="_blank" data-tooltip="邮件:chinalixs@qq.com" data-position="top" data-delay="50">
    <i class="fa fa-envelope-open"></i>
</a>

<a href="http://wpa.qq.com/msgrd?v=3&uin=6956820&site=qq&menu=yes" class="tooltipped" data-tooltip="QQ: 6956820" data-position="top" data-delay="50">
    <i class="fa fa-qq"></i>
</a>
</div>
</div>

            </div>
        </div>

        
    </nav>
</header>



<div class="bg-cover post-cover" style="background-image: url('/medias/featureimages/18.jpg')">
    <div class="container">
        <div class="row">
            <div class="col s12 m12 l12">
                <div class="brand">
                    <div class="description center-align post-title">
                        WebRTC04KurentoDemo流程分析
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>



<main class="post-container content">

    
    <link rel="stylesheet" href="/libs/tocbot/tocbot.css">
<style>
    #articleContent h1,
    #articleContent h2,
    #articleContent h3,
    #articleContent h4,
    #articleContent h5,
    #articleContent h6 {
        padding-top: 76px;
        margin-top: -76px;
    }

    #articleContent h1 {
        line-height: 3.5rem;
    }

    #articleContent h2 {
        line-height: 3.2rem;
    }

    #articleContent h3 {
        line-height: 2.8rem;
    }

    #articleContent h4 {
        line-height: 2.5rem;
    }

    #articleContent h5 {
        line-height: 2.2rem;
    }

    #articleContent h6 {
        line-height: 1.9rem;
    }

    #articleContent :focus {
        outline: none;
    }

    .toc-fixed {
        position: fixed;
        top: 64px;
    }

    .toc-widget {
        padding-left: 20px;
    }

    .toc-widget .toc-title {
        margin: 35px 0 15px 0;
        padding-left: 17px;
        font-size: 1.5rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    .toc-widget ol {
        padding: 0;
        list-style: none;
    }

    #toc-content ol {
        padding-left: 10px;
    }

    #toc-content ol li {
        padding-left: 10px;
    }

    #toc-content .toc-link:hover {
        color: #42b983;
        font-weight: 700;
        text-decoration: underline;
    }

    #toc-content .toc-link::before {
        background-color: transparent;
        max-height: 25px;
    }

    #toc-content .is-active-link {
        color: #42b983;
    }

    #toc-content .is-active-link::before {
        background-color: #42b983;
    }
</style>
<div class="row">
    <div class="col s12 m12 l9">
        <!-- 文章内容详情 -->
<div id="artDetail">
    <div class="card">
        <div class="card-content article-info">
            
            <div class="article-tag">
                
                <a href="/tags/js/" target="_blank">
                    <span class="chip bg-color">js</span>
                </a>
                
            </div>
            
            <div class="post-info">
                
                <span class="post-cate">
                    <i class="fa fa-bookmark fa-fw icon-category"></i>
                    
                    <a href="/categories/WebRTC/" class="post-category" target="_blank">
                        WebRTC
                    </a>
                    
                </span>
                

                <span class="post-date">
                    <i class="fa fa-clock-o fa-fw"></i>2018-08-28
                </span>
            </div>
        </div>
        <hr>
        <div class="card-content article-card-content">
            <div id="articleContent">
                <blockquote>
<p>今天的学习可以说是以失败告终了吧。也就知道了用js动态调试。大体看懂了participant.js和conference.js。但最大头的是kurento.js</p>
</blockquote>
<a id="more"></a>
<h1 id="关于频繁出现的-ICE-candidate："><a href="#关于频繁出现的-ICE-candidate：" class="headerlink" title="关于频繁出现的 ICE candidate："></a>关于频繁出现的 ICE candidate：</h1><p><strong>ICE</strong> stands for <strong>Interactive Connectivity Establishment</strong> , its a techniques used in NAT( network address translator ) for <code>establishing communication for VOIP, peer-peer, instant-messaging, and other kind of interactive media.</code></p>
<p>Typically <strong>ice candidate</strong> provides the information about the IPaddress and port from where the data is going to be exchanged.</p>
<p>It’s format is something like follows</p>
<p>a=candidate:1 1 <strong>UDP</strong> 2130706431 <strong>192.168.1.102 1816</strong> typ <strong>host</strong></p>
<p>here <code>UDP</code> specifies the protocol to be used, the <code>typ host</code> specifies which type of ice candidates it is, host means the candidates is generated within the firewall. If you use <code>wireshark</code> to monitor the traffic then you can see the ports that are used for data transfer are same as the one present in ice-candidates.</p>
<p>Another type is <code>relay</code> , which denotes this candidates can be used when communication is to be done outside the firewall.</p>
<p>It may contain more information depending on browser you are using. Many time i have seen 8-12 ice-candidates are generated by browser.</p>
<hr>
<p>Every ICE contains ‘a node’ of your network, until it has reached the outside. By this you send these ICE’s to the other peer, so they know through what connection points they can reach you. See it as a large building: one is in the building, and needs to tell the other (who is not familiar) how to walk through it. Same here, if I have a lot of network devices, the incoming connection somehow needs to find the right way to my computer. By providing all nodes, the RTC connection finds the shortest route itself. So when you would connect to the computer next to you, which is connected to the same router/switch/whatever, it uses all ICE’s and determine the shortest, and that is directly through that point. That your collegue got less ICE candidates has to do with the ammount of devices it has to go through. Please note that every network adapter inside your computer which has an IP adress (I have a vEthernet switch from hyper-v) it also creates an ICE for it.</p>
<p>参考链接：<a href="https://stackoverflow.com/a/21071464" target="_blank" rel="noopener">https://stackoverflow.com/a/21071464</a></p>
<p>Demo是王老师搭建了运行在服务器的，先通过给两个主要的js文件(<code>participate.js和conference.js</code>)下断点来弄明白流程吧。</p>
<p><del>我先建立一个房间登录用户banana房间号1234。然后用另一个浏览器进去开始调试。在<code>participant.js</code>第30行下了断点。</del></p>
<ul>
<li><p><del>输入名字apple和房间号1234后，进入<code>Participant(name)</code>函数。name就是apple。仔细看这好像是Participant的类啊。整个<code>participant.js</code>就这一个函数。</del></p>
</li>
<li><p><del>然后这个函数开始写html</del></p>
<p><del>在一个container中把name、video框啥的加入。还会有video一些参数的设置。然后return这个container</del></p>
</li>
<li><p><del>到了<code>conferenceroom.js</code>，有个参与者的数组，下标是name，加入了刚刚的的用户</del></p>
</li>
<li><p><del>回到<code>participant.js</code>读到了banana。又是一系列的写入html。</del></p>
</li>
<li><p><del>然后到了<code>conferenceroom.js</code>的<code>receiveVideo(sender)</code>函数。就是接受sender这个用户发来的Video。</del></p>
<blockquote>
<p><del>一会儿建立一个3人的看看sender会变成啥样。怎么接。</del></p>
</blockquote>
</li>
<li><p><del>跳转到 <code>conference.js</code>的<code>ws.onmessage = function(message)</code>,其中message里面有数据：<code>&quot;id&quot;:&quot;existingParticipants&quot;,&quot;data&quot;:[&quot;banana&quot;]</code>和源<code>origin: &quot;wss://192.168.139.218:8443&quot;</code></del></p>
<p><del>message里的数据是JSON格式的。然后解包存到了<u>parseMessage</u>这个变量。通过<strong>id</strong>判断进去什么case。</del></p>
<p><del>明显我现在是属于存在用户的情况：</del></p>
<pre class="line-numbers language-javascript"><code class="language-javascript"><span class="token keyword">case</span> <span class="token string">'existingParticipants'</span><span class="token punctuation">:</span>
        <span class="token function">onExistingParticipants</span><span class="token punctuation">(</span>parsedMessage<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">break</span><span class="token punctuation">;</span>
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>
<p><del>下面看具体的<code>onExistingParticipants(parsedMessage);</code>执行了什么:</del></p>
<ul>
<li><del>变量constranits是控制网页video大小的</del></li>
<li><del>控制台输出：apple在房间注册</del></li>
<li><del>新建一个Participate对象</del></li>
</ul>
<p><del>break</del></p>
<hr>
</li>
</ul>
<ul>
<li><p><del>至此图像还没有在网页显示。进入了<code>kurento-utils.js</code>。应该是实现WebRTC的了。</del></p>
</li>
<li><p><del><code>start()</code>函数。不知道为啥，直接到了<code>if (mode !== &#39;recvonly&#39; &amp;&amp; !videoStream &amp;&amp; !audioStream)</code>  –&gt;</del></p>
<pre class="line-numbers language-javascript"><code class="language-javascript">navigator<span class="token punctuation">.</span>mediaDevices<span class="token punctuation">.</span><span class="token function">getUserMedia</span><span class="token punctuation">(</span>constraints<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span>stream<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                videoStream <span class="token operator">=</span> stream<span class="token punctuation">;</span>
                <span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">catch</span><span class="token punctuation">(</span>callback<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>
<p><del>其中stream是一个MediaSteam.上午自己看资料看到有MediaSteamAPI。然后又<code>start()</code>有点懵。</del></p>
<hr>
</li>
</ul>
<ul>
<li><p><del>到了<code>window.RTCPeerConnection</code>又是一阵懵之后。</del></p>
</li>
<li><p><del>回到了<code>conference.js`</code>ws.onmessage = funciton(message)<code>解JSON数据包。并出现了apple的画面。此时的messsage里id成了</code>receiveVideoAnser`,通过id判断进入case。</del></p>
</li>
<li><p><del>break后又在ws.onmessage解JSON。id成了<code>&quot;iceCandidate&quot;</code></del></p>
<p><del>进入iceCandidate的case：参与者的数组中取到apple然后<code>.rtcPeer.addIceCandidate()</code>是加入了参与者？但是也没看到读取banana啊。只读到一串这个：<code>&quot;candidate:4 1 UDP 2013266431 2400:dd0a:1005:1390:250:56ff:fe86:a0c4 30325 typ host&quot;</code></del></p>
</li>
<li><p><del>回到了<code>window.RTCPeerConnection</code>执行<code>resolve()</code>解码？</del></p>
</li>
</ul>
<hr>
<p>上面调试遇到一个问题就是，加了断点会在死循环里出不来啊。</p>
<p>我懂了。我应该在每种情况下加不同的断点。然后看代码是怎么走的。就是说我之前折腾这半天顶多就知道了个新建Participate对象的事。重来吧。</p>
<hr>
<ol>
<li>在<code>conference.js</code>的前4个case中下断点</li>
<li>第一个用户apple进入1234房间，分析</li>
<li>第二个用户banana进入1234房间，分析</li>
<li>第三个用户cabbage进入1234房间，分析</li>
<li>第二个用户banana退出1234房间，分析</li>
</ol>
<ul>
<li>第一个用户apple进入1234房间<ul>
<li>虽然之前没有人。但还是进入了existingParticipants情况下。<code>function onExistingParticipants(msg)</code>其中msg中：<code>{id: &quot;existingParticipants&quot;, data: Array(0)}</code></li>
<li>控制台输出，apple在房间注册</li>
<li>新建Participate对象<code>participant = new Participant(name);</code> name就是“apple” ，这个过程会在HTML写入video框，但还没有读到数据</li>
<li>存入数组participants[name]</li>
<li>读video</li>
<li><code>participant.rtcPeer</code> 进入了<code>kurento-utils.js</code>这里面好复杂没看懂</li>
<li>break了<code>case &#39;existingParticipants&#39;</code></li>
<li>通过<code>this.offerToReceiveVideo</code>进入了<code>receiveVideoResponse</code>这个case。<code>receiveVideoResponse(result)</code>其中result内容有id、name和adpAnswer</li>
<li>end？</li>
</ul>
</li>
</ul>
<hr>
<p>又去请教了下王老师。看来我的重点还是要去看</p>
<p><code>kurento-utils.js</code>研究明白这个才是最重要的。</p>
<p>问题的关键就在于我要摸索出什么该看什么不该看。</p>
<hr>
<p>下班后王老师一走。Demo进不去了。找了找文档，想自己搭建一下呢。发现要JDK和mvn。电脑没这么多空间了。贼尴尬。</p>
<p><a href="http://www.kurento.org" target="_blank" rel="noopener">http://www.kurento.org</a></p>
<p>Demo官网。</p>
<blockquote>
<p>后来发现这个Demo是搭建在实验室的服务器上的。必须是Ubuntu环境。</p>
</blockquote>
<h1 id="js调试知识点"><a href="#js调试知识点" class="headerlink" title="js调试知识点"></a>js调试知识点</h1><ul>
<li><p>控制台输入 <code>$(this)</code>即可得到选择的元素</p>
</li>
<li><p>输入变量名可查看这个变量</p>
<blockquote>
<p> 但要在加了断点的情况下才能看到那些局部变量哦</p>
</blockquote>
</li>
<li><p>可以边调试边打断点和去断点啊！</p>
</li>
<li><p>王老师说的对，这东西还是得多调。有了经验了以后就会打了。</p>
</li>
</ul>

            </div>
            <hr>

            

            <link rel="stylesheet" type="text/css" href="/libs/share/css/share.min.css">

<div id="article-share">
    
    <div class="social-share" data-disabled="qzone" data-wechat-qrcode-helper="<p>微信里点“发现”->“扫一扫”二维码便可查看分享。</p>"></div>
    
</div>

<script src="/libs/share/js/social-share.min.js"></script>

            <div class="reprint">
                <p>
                    <span class="reprint-tip">转载请注明: </span>
                    <a href="https://xuanshan.gitee.io" class="b-link-green">炫杉</a>
                    <i class="fa fa-angle-right fa-lg fa-fw text-color"></i>
                    <a href="/WebRTC/WebRTC04Kurento流程分析/" class="b-link-green">WebRTC04KurentoDemo流程分析</a>
                </p>
            </div>
        </div>
    </div>

    

    

    

    
    <div class="livere-card card" data-aos="fade-up">
    <!-- 来必力City版安装代码 -->
    <div id="lv-container" class="card-content" data-id="city" data-uid="MTAyMC8yOTg2My82NDI5">
        <script type="text/javascript">
            (function (d, s) {
                let j, e = d.getElementsByTagName(s)[0];
                if (typeof LivereTower === 'function') {
                    return;
                }

                j = d.createElement(s);
                j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
                j.async = true;

                e.parentNode.insertBefore(j, e);
            })(document, 'script');
        </script>
        <noscript>为正常使用来必力评论功能请激活JavaScript。</noscript>
    </div>
    <!-- City版安装代码已完成 -->
</div>
    

    

<article id="prenext-posts" class="prev-next articles">
    <div class="row article-row">
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge left-badge text-color">上一篇</div>
            <div class="card">
                <a href="/WebRTC/WebRTC05入门教程02/">
                    <div class="card-image">
                        
                        
                        <img src="/medias/featureimages/1.jpg" class="responsive-img" alt="WebRTC05入门教程02">
                        
                        <span class="card-title">WebRTC05入门教程02</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary">p2p的核心RTCPeerConnection APIs的介绍

RTCPeerConnection APIs简单样例：var pc = RTCPeerConnection(config);
config包含 key, iceServers</div>
                    <div class="publish-info">
                        <span class="publish-date">
                            <i class="fa fa-clock-o fa-fw icon-date"></i>2018-08-30
                        </span>
                        <span class="publish-author">
                            
                            <i class="fa fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/categories/WebRTC/" class="post-category" target="_blank">
                                    WebRTC
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/tags/Demo/" target="_blank">
                        <span class="chip bg-color">Demo</span>
                    </a>
                    
                    <a href="/tags/tutorial/" target="_blank">
                        <span class="chip bg-color">tutorial</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge right-badge text-color">下一篇</div>
            <div class="card">
                <a href="/WebRTC/WebRTC03入门教程01/">
                    <div class="card-image">
                        
                        
                        <img src="/medias/featureimages/2.jpg" class="responsive-img" alt="WebRTC03入门教程01">
                        
                        <span class="card-title">WebRTC03入门教程01</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary">WebRTC教程

HomeWebRTC（网页实时通讯）技术可以很容易地让人们在网页实现音频、视频连接。这个教程中，我们会解释如何用WebRTC快速建立一个peer-to-peer的连接。
受众开发者。条件WebRTC用于赋予浏览器和移动A</div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="fa fa-clock-o fa-fw icon-date"></i>2018-08-27
                            </span>
                        <span class="publish-author">
                            
                            <i class="fa fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/categories/WebRTC/" class="post-category" target="_blank">
                                    WebRTC
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/tags/tutorial/" target="_blank">
                        <span class="chip bg-color">tutorial</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
    </div>
</article>
</div>
    </div>
    <div class="col l3 hide-on-med-and-down">
        <div class="toc-widget">
            <div class="toc-title">目录</div>
            <div id="toc-content">

            </div>
        </div>
    </div>
</div>

<script src="/libs/tocbot/tocbot.min.js"></script>
<script>
    $(function () {
        tocbot.init({
            tocSelector: '#toc-content',
            contentSelector: '#articleContent',
            headingSelector: 'h1,h2, h3, h4'
        });

        // modify the toc link href to support Chinese.
        let i = 0;
        let tocHeading = 'toc-heading-';
        $('#toc-content a').each(function () {
            $(this).attr('href', '#' + tocHeading + (++i));
        });

        // modify the heading title id to support Chinese.
        i = 0;
        $('#articleContent').children('h1,h2, h3, h4').each(function () {
            $(this).attr('id', tocHeading + (++i));
        });

        // Set scroll toc fixed.
        let tocHeight = parseInt($(window).height() * 0.4 - 64);
        let $tocWidget = $('.toc-widget');
        $(window).scroll(function () {
            let scroll = $(window).scrollTop();
            /* add post toc fixed. */
            if (scroll > tocHeight) {
                $tocWidget.addClass('toc-fixed');
            } else {
                $tocWidget.removeClass('toc-fixed');
            }
        });
    });
</script>
    

</main>

<footer class="page-footer bg-color">
    <div class="container row center-align">
        <div class="col s12 m8 l8 copy-right">
            &copy;<a href="https://o--o.win" target="_blank">炫杉2018</a> 
            <a href="https://hexo.io/" target="_blank">Hexo</a> 强力驱动
              主题 <a href="https://github.com/blinkfox/hexo-theme-matery" target="_blank">matery</a>        </div>
        <div class="col s12 m4 l4 social-link"><a href="https://github.com/ixsim" class="tooltipped" target="_blank" data-tooltip="访问我的GitHub" data-position="top" data-delay="50">
    <i class="fa fa-github"></i>
</a>

<a href="mailto:chenjiayin1990@163.com" class="tooltipped" target="_blank" data-tooltip="邮件:chinalixs@qq.com" data-position="top" data-delay="50">
    <i class="fa fa-envelope-open"></i>
</a>

<a href="http://wpa.qq.com/msgrd?v=3&uin=6956820&site=qq&menu=yes" class="tooltipped" data-tooltip="QQ: 6956820" data-position="top" data-delay="50">
    <i class="fa fa-qq"></i>
</a>
</div>
    </div>
</footer>

<div class="progress-bar"></div>


<!-- 搜索遮罩框 -->
<div id="searchModal" class="modal">
    <div class="modal-content">
        <div class="search-header">
            <span class="title">搜索</span>
            <input type="search" id="searchInput" name="s" placeholder="请输入搜索的关键字" class="search-input" autofocus>
        </div>
        <div id="searchResult"></div>
    </div>
</div>

<script src="/js/search.js"></script>
<script type="text/javascript">
    searchFunc("/" + "search.xml", 'searchInput', 'searchResult');
</script>
<!-- 回到顶部按钮 -->
<div id="backTop" class="top-scroll">
    <a class="btn-floating btn-large waves-effect waves-light" href="#!">
        <i class="fa fa-angle-up"></i>
    </a>
</div>


<script src="/libs/materialize/js/materialize.min.js"></script>
<script src="/libs/masonry/masonry.pkgd.min.js"></script>
<script src="/libs/aos/aos.js"></script>
<script src="/libs/scrollprogress/scrollProgress.min.js"></script>
<script src="/libs/lightGallery/js/lightgallery-all.min.js"></script>
<script src="/js/matery.js"></script>
</body>
</html>